home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / telecomm / sticpsrc.lzh / SOURCE.ARC / IP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-07-31  |  9.9 KB  |  389 lines

  1. /* Upper half of IP, consisting of send/receive primitives, including
  2.  * fragment reassembly, for higher level protocols.
  3.  * Not needed when running as a standalone gateway.
  4.  */
  5. #include "global.h"
  6. #include "mbuf.h"
  7. #include "timer.h"
  8. #include "internet.h"
  9. #include "iface.h"
  10. #include "ip.h"
  11. #include "icmp.h"
  12.  
  13. #define    TLB    SEC2TICK(30)    /* Reassembly limit time */
  14.  
  15. void ip_recv();
  16.  
  17. char ip_ttl = MAXTTL;    /* Default time-to-live for IP datagrams */
  18.  
  19. struct reasm *reasmq;
  20.  
  21. #define    INSERT    0
  22. #define    APPEND    1
  23. #define    PREPEND    2
  24.  
  25. /* Send an IP datagram. Modeled after the example interface on p 32 of
  26.  * RFC 791
  27.  */
  28. int
  29. ip_send(source,dest,protocol,tos,ttl,bp,length,id,df)
  30. int32 source;            /* source address */
  31. int32 dest;            /* Destination address */
  32. char protocol;            /* Protocol */
  33. char tos;            /* Type of service */
  34. char ttl;            /* Time-to-live */
  35. struct mbuf *bp;        /* Data portion of datagram */
  36. int16 length;            /* Optional length of data portion */
  37. int16 id;            /* Optional identification */
  38. char df;            /* Don't-fragment flag */
  39. {
  40.     struct mbuf *htonip(),*tbp;
  41.     struct ip ip;        /* Pointer to IP header */
  42.     static int16 id_cntr;    /* Datagram serial number */
  43.     int ip_route();        /* Datagram router */
  44.  
  45.     if(length == 0 && bp != NULLBUF)
  46.         length = len_mbuf(bp);
  47.     if(id == 0)
  48.         id = id_cntr++;        
  49.     if(ttl == 0)
  50.         ttl = ip_ttl;
  51.  
  52.     /* Fill in IP header */
  53.     ip.tos = tos;
  54.     ip.length = IPLEN + length;
  55.     ip.id = id;
  56.     if(df)
  57.         ip.fl_offs = DF;
  58.     else
  59.         ip.fl_offs = 0;
  60.     ip.ttl = ttl;
  61.     ip.protocol = protocol;
  62.     ip.source = source;
  63.     ip.dest = dest;
  64.     ip.optlen = 0;
  65.     if((tbp = htonip(&ip,bp)) == NULLBUF){
  66.         free_p(bp);
  67.         return -1;
  68.     }
  69.     return ip_route(tbp,0);        /* Toss it to the router */
  70. }
  71.  
  72. /* Reassemble incoming IP fragments and dispatch completed datagrams
  73.  * to the proper transport module
  74.  */
  75. void
  76. ip_recv(ip,bp,rxbroadcast)
  77. struct ip *ip;        /* Extracted IP header */
  78. struct mbuf *bp;    /* Data portion */
  79. char rxbroadcast;    /* True if received on subnet broadcast address */
  80. {
  81.     struct mbuf *fraghandle();
  82.     void (*recv)();    /* Function to call with completed datagram */
  83.     void tcp_input(),udp_input(),icmp_input();
  84.  
  85.     /* Initial check for protocols we can't handle */
  86.     switch(uchar(ip->protocol)){
  87.     case TCP_PTCL:
  88.         recv = tcp_input;
  89.         break;
  90.     case UDP_PTCL:
  91.         recv = udp_input;
  92.         break;
  93.     case ICMP_PTCL:
  94.         recv = icmp_input;
  95.         break;
  96.     default:
  97.         /* Send an ICMP Protocol Unknown response... */
  98.         ip_stats.badproto++;
  99.         /* ...unless it's a broadcast */
  100.         if(!rxbroadcast){
  101.             icmp_output(ip,bp,DEST_UNREACH,PROT_UNREACH,(union icmp_args *)NULL);
  102.         }
  103.         free_p(bp);
  104.         return;
  105.     }
  106.     /* If we have a complete packet, call the next layer
  107.      * to handle the result. Note that fraghandle passes back
  108.      * a length field that does NOT include the IP header
  109.      */
  110.     if((bp = fraghandle(ip,bp)) != NULLBUF)
  111.         (*recv)(bp,ip->protocol,ip->source,ip->dest,ip->tos,
  112.             ip->length - (IPLEN + ip->optlen),rxbroadcast);
  113. }
  114. /* Process IP datagram fragments
  115.  * If datagram is complete, return it with ip->length containing the data
  116.  * length (MINUS header); otherwise return NULLBUF
  117.  */
  118. static
  119. struct mbuf *
  120. fraghandle(ip,bp)
  121. struct ip *ip;        /* IP header, host byte order */
  122. struct mbuf *bp;    /* The fragment itself */
  123. {
  124.     void freefrag(),free_reasm();
  125.     struct reasm *lookup_reasm(),*creat_reasm();
  126.     register struct reasm *rp; /* Pointer to reassembly descriptor */
  127.     struct frag *lastfrag,*nextfrag,*tfp,*newfrag();
  128.     struct mbuf *tbp;
  129.     int16 i;
  130.     int16 offset;        /* Index of first byte in fragment */
  131.     int16 last;        /* Index of first byte beyond fragment */
  132.     char mf;        /* 1 if not last fragment, 0 otherwise */
  133.  
  134.     offset = (ip->fl_offs & F_OFFSET) << 3;    /* Convert to bytes */
  135.     last = offset + ip->length - (IPLEN + ip->optlen);
  136.     mf = (ip->fl_offs & MF) ? 1 : 0;
  137.  
  138.     rp = lookup_reasm(ip);
  139.     if(offset == 0 && !mf){
  140.         /* Complete datagram received. Discard any earlier fragments */
  141.         if(rp != NULLREASM)
  142.             free_reasm(rp);
  143.  
  144.         return bp;
  145.     }
  146.     if(rp == NULLREASM){
  147.         /* First fragment; create new reassembly descriptor */
  148.         if((rp = creat_reasm(ip)) == NULLREASM){
  149.             /* No space for descriptor, drop fragment */
  150.             free_p(bp);
  151.             return NULLBUF;
  152.         }
  153.     }
  154.     /* Keep restarting timer as long as we keep getting fragments */
  155.     stop_timer(&rp->timer);
  156.     start_timer(&rp->timer);
  157.  
  158.     /* If this is the last fragment, we now know how long the
  159.      * entire datagram is; record it
  160.      */
  161.     if(!mf)
  162.         rp->length = last;
  163.  
  164.     /* Set nextfrag to the first fragment which begins after us,
  165.      * and lastfrag to the last fragment which begins before us
  166.      */
  167.     lastfrag = NULLFRAG;
  168.     for(nextfrag = rp->fraglist;nextfrag != NULLFRAG;nextfrag = nextfrag->next){
  169.         if(nextfrag->offset > offset)
  170.             break;
  171.         lastfrag = nextfrag;
  172.     }
  173.     /* Check for overlap with preceeding fragment */
  174.     if(lastfrag != NULLFRAG  && offset < lastfrag->last){
  175.         /* Strip overlap from new fragment */
  176.         i = lastfrag->last - offset;
  177.         pullup(&bp,NULLCHAR,i);
  178.         if(bp == NULLBUF)
  179.             return NULLBUF;    /* Nothing left */
  180.         offset += i;
  181.     }
  182.     /* Look for overlap with succeeding segments */
  183.     for(; nextfrag != NULLFRAG; nextfrag = tfp){
  184.         tfp = nextfrag->next;    /* save in case we delete fp */
  185.  
  186.         if(nextfrag->offset >= last)
  187.             break;    /* Past our end */
  188.         /* Trim the front of this entry; if nothing is
  189.          * left, remove it.
  190.          */
  191.         i = last - nextfrag->offset;
  192.         pullup(&nextfrag->buf,NULLCHAR,i);
  193.         if(nextfrag->buf == NULLBUF){
  194.             /* superseded; delete from list */
  195.             if(nextfrag->prev != NULLFRAG)
  196.                 nextfrag->prev->next = nextfrag->next;
  197.             else
  198.                 rp->fraglist = nextfrag->next;
  199.             if(tfp->next != NULLFRAG)
  200.                 nextfrag->next->prev = nextfrag->prev;
  201.             freefrag(nextfrag);
  202.         } else
  203.             nextfrag->offset = last;
  204.     }
  205.     /* Lastfrag now points, as before, to the fragment before us;
  206.      * nextfrag points at the next fragment. Check to see if we can
  207.      * join to either or both fragments.
  208.      */
  209.     i = INSERT;
  210.     if(lastfrag != NULLFRAG && lastfrag->last == offset)
  211.         i |= APPEND;
  212.     if(nextfrag != NULLFRAG && nextfrag->offset == last)
  213.         i |= PREPEND;
  214.     switch(i){
  215.     case INSERT:    /* Insert new desc between lastfrag and nextfrag */
  216.         tfp = newfrag(offset,last,bp);
  217.         tfp->prev = lastfrag;
  218.         tfp->next = nextfrag;
  219.         if(lastfrag != NULLFRAG)
  220.             lastfrag->next = tfp;    /* Middle of list */
  221.         else
  222.             rp->fraglist = tfp;    /* First on list */
  223.         if(nextfrag != NULLFRAG)
  224.             nextfrag->prev = tfp;
  225.         break;
  226.     case APPEND:    /* Append to lastfrag */
  227.         append(&lastfrag->buf,bp);
  228.         lastfrag->last = last;    /* Extend forward */
  229.         break;
  230.     case PREPEND:    /* Prepend to nextfrag */
  231.         tbp = nextfrag->buf;
  232.         nextfrag->buf = bp;
  233.         append(&nextfrag->buf,tbp);
  234.         nextfrag->offset = offset;    /* Extend backward */
  235.         break;
  236.     case (APPEND|PREPEND):
  237.         /* Consolidate by appending this fragment and nextfrag
  238.          * to lastfrag and removing the nextfrag descriptor
  239.          */
  240.         append(&lastfrag->buf,bp);
  241.         append(&lastfrag->buf,nextfrag->buf);
  242.         nextfrag->buf = NULLBUF;
  243.         lastfrag->last = nextfrag->last;
  244.  
  245.         /* Finally unlink and delete the now unneeded nextfrag */
  246.         lastfrag->next = nextfrag->next;
  247.         if(nextfrag->next != NULLFRAG)
  248.             nextfrag->next->prev = lastfrag;
  249.         freefrag(nextfrag);
  250.         break;
  251.     }
  252.     if(rp->fraglist->offset == 0 && rp->fraglist->next == NULLFRAG 
  253.         && rp->length != 0){
  254.         /* We've gotten a complete datagram, so extract it from the
  255.          * reassembly buffer and pass it on.
  256.          */
  257.         bp = rp->fraglist->buf;
  258.         rp->fraglist->buf = NULLBUF;
  259.         /* Tell IP the entire length */
  260.         ip->length = rp->length + (IPLEN + ip->optlen);
  261.         free_reasm(rp);
  262.         return bp;
  263.     } else
  264.         return NULLBUF;
  265. }
  266. static struct reasm *
  267. lookup_reasm(ip)
  268. struct ip *ip;
  269. {
  270.     register struct reasm *rp;
  271.  
  272.     for(rp = reasmq;rp != NULLREASM;rp = rp->next){
  273.         if(ip->source == rp->source && ip->dest == rp->dest
  274.          && ip->protocol == rp->protocol && ip->id == rp->id)
  275.             return rp;
  276.     }
  277.     return NULLREASM;
  278. }
  279. #ifdef    FOO
  280. static
  281. int16
  282. hash_reasm(source,dest,protocol,id)
  283. int32 source;
  284. int32 dest,
  285. char protocol;
  286. int16 id;
  287. {
  288.     register int16 hval;
  289.  
  290.     hval = loword(source);
  291.     hval ^= hiword(source);
  292.     hval ^= loword(dest);
  293.     hval ^= hiword(dest);
  294.     hval ^= uchar(protocol);
  295.     hval ^= id;
  296.     hval %= RHASH;
  297.     return hval;
  298. }
  299. #endif
  300. /* Create a reassembly descriptor,
  301.  * put at head of reassembly list
  302.  */
  303. static struct reasm *
  304. creat_reasm(ip)
  305. register struct ip *ip;
  306. {
  307.     register struct reasm *rp;
  308.     void ip_timeout();
  309.  
  310.     if((rp = (struct reasm *)calloc(1,sizeof(struct reasm))) == NULLREASM)
  311.         return rp;    /* No space for descriptor */
  312.     rp->source = ip->source;
  313.     rp->dest = ip->dest;
  314.     rp->id = ip->id;
  315.     rp->protocol = ip->protocol;
  316.     rp->timer.start = TLB;
  317.     rp->timer.func = ip_timeout;
  318.     rp->timer.arg = (char *)rp;
  319.  
  320.     rp->next = reasmq;
  321.     if(rp->next != NULLREASM)
  322.         rp->next->prev = rp;
  323.     reasmq = rp;
  324.     return rp;
  325. }
  326.  
  327. /* Free all resources associated with a reassembly descriptor */
  328. static void
  329. free_reasm(rp)
  330. register struct reasm *rp;
  331. {
  332.     register struct frag *fp;
  333.  
  334.     stop_timer(&rp->timer);
  335.     /* Remove from list of reassembly descriptors */
  336.     if(rp->prev != NULLREASM)
  337.         rp->prev->next = rp->next;
  338.     else
  339.         reasmq = rp->next;
  340.     if(rp->next != NULLREASM)
  341.         rp->next->prev = rp->prev;
  342.     /* Free any fragments on list, starting at beginning */
  343.     while((fp = rp->fraglist) != NULLFRAG){
  344.         rp->fraglist = fp->next;
  345.         free_p(fp->buf);
  346.         free((char *)fp);
  347.     }
  348.     free((char *)rp);
  349. }
  350.  
  351. /* Handle reassembly timeouts by deleting all reassembly resources */
  352. static void
  353. ip_timeout(arg)
  354. int *arg;
  355. {
  356.     register struct reasm *rp;
  357.  
  358.     rp = (struct reasm *)arg;
  359.     free_reasm(rp);
  360. }
  361. /* Create a fragment */
  362. static
  363. struct frag *
  364. newfrag(offset,last,bp)
  365. int16 offset,last;
  366. struct mbuf *bp;
  367. {
  368.     struct frag *fp;
  369.  
  370.     if((fp = (struct frag *)calloc(1,sizeof(struct frag))) == NULLFRAG){
  371.         /* Drop fragment */
  372.         free_p(bp);
  373.         return NULLFRAG;
  374.     }
  375.     fp->buf = bp;
  376.     fp->offset = offset;
  377.     fp->last = last;
  378.     return fp;
  379. }
  380. /* Delete a fragment, return next one on queue */
  381. static
  382. void
  383. freefrag(fp)
  384. struct frag *fp;
  385. {
  386.     free_p(fp->buf);
  387.     free((char *)fp);
  388. }
  389.